<?php

namespace app\sys\service;

use app\admin\model\Token;
use app\admin\model\UserPvLog;
use app\sys\model\Conn;
use app\sys\model\Hint;
use app\sys\model\SensitiveWord;
use GatewayClient\Gateway;
use \app\admin\model\Chat;
use \app\admin\model\User;
use \app\admin\model\Staff;
use \app\admin\model\ChatLog;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\DbException;
use think\facade\Env;
use think\facade\Log;
use wechatcom\WechatComment;
use wework\WeWork;

class GateCli extends Gateway
{
    /**
     * 向客服发送
     */
    const toTypeSta = 1;## 向客服发送
    /**
     * 向客户发送
     */
    const toTypeUse = 0;## 向客户发送
    /**
     * 发送列表 标识
     */
    const sendTypeList = "send_list_new";
    /**
     * 发送消息
     */
    const sendTypeInfo = "send";
    /**
     * 发送消息
     */
    const sendTypeNo = "sys";
    /**
     * ws 客服发送标识
     * @var string
     */
    public static $staPre = 'sta_';
    /**
     * ws 客户发送标识
     * @var string
     */
    public static $usePre = 'use_';

    public static $sendType;

    public function __construct($sendType = "")
    {
        self::$registerAddress = \think\facade\Env::get("GATEWAY.REGIS_ADDRESS");
    }

    /**
     * 获取发送类型
     */
    public function setSendType(): string
    {
        if (self::$sendType == "") return self::sendTypeInfo;
        return self::sendTypeNo;
    }

    /**
     * 获取客服ws 发送编号
     * @param $staffNo
     * @return string
     */
    public function getStaffNo($staffNo): string
    {
        return self::$staPre . $staffNo;
    }

    /**
     * 获取客户ws 发送编号
     * @param $userNo
     * @return string
     */
    public function getUserNo($userNo): string
    {
        return self::$usePre . $userNo;
    }

    /**
     * 向谁发送设置
     * @param $staffNo
     * @param $userNo
     * @param $usrType
     * @return string[]
     */
    public function sendToSet($staffNo, $userNo, $usrType): array
    {
        // 0 向客户发送  1 向客服发送
        if ($usrType == self::toTypeSta) {
            $toUidNo = $this->getStaffNo($staffNo);
            $seUidNo = $this->getUserNo($userNo);

            $sendToNo = "staff";
        } else {
            $toUidNo = $this->getUserNo($userNo);
            $seUidNo = $this->getStaffNo($staffNo);

            $sendToNo = "user";
        }
        return [$toUidNo, $seUidNo, $sendToNo];
    }

    /**
     * 多客户端绑定 官网
     * @param $clientId
     * @param $PreNo
     * @param $id
     * @param $isMen
     */
    public function newManyClient($clientId, $PreNo, $id, $isMen)
    {
//        if (self::isUidOnline($PreNo)) {
//            $arrCli = self::getClientIdByUid($PreNo);
//            foreach ($arrCli as $k => $v) {
//                Log::info("wsUserBind:{$v}-{$PreNo}");
//                self::unbindUid($v, $PreNo);
//                self::closeClient($v);
//            }
//        }
        // session
        self::setSession($clientId, ["{$clientId}no" => $PreNo, "id" => $id, "isMen" => $isMen]);
        // 前缀（主要区别）
        self::bindUid($clientId, $PreNo);
    }

    /**
     * 绑定 后台
     * @param $clientId
     * @param $PreNo
     * @param $id
     */
    public function newClient($clientId, $PreNo, $id)
    {
        if (self::isUidOnline($PreNo)) {
            $arrCli = self::getClientIdByUid($PreNo);
            foreach ($arrCli as $k => $v) {
                Log::info("wsUserBind:{$v}-{$PreNo}");
//                self::unbindUid($v, $PreNo);
//                self::closeClient($v);
            }
        }
        // session
        self::setSession($clientId, ["{$clientId}no" => $PreNo, "id" => $id]);
        // 前缀（主要区别）
        self::bindUid($clientId, $PreNo);
    }

    /**
     * 发送消息给用户
     * @param $staff
     * @param $user
     * @param $agent
     * @param $store
     * @param $data
     * @param int $usrType
     * @param int $isMen
     * @param int $staffStatus
     * @param array $sendOtherNo
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function SendToUser($staff, $user, $agent, $store, $data, $usrType = 0, $isMen = 0, $staffStatus = 0, $sendOtherNo = []): string
    {
        // 敏感词
        Log::info("autoReplayInfo_err0:");
        $data = SensitiveWord::searchWordN($data, $user, $staff);
        Log::info("autoReplayInfo_err1:");

        $u = Db::table("ic_user")->where("id", $user)->find();
        if (empty($u)) {
            return "用户不存在";
        }
        if ($u && $isMen == 0) {
            $isMen = User::getIsMen($u["mobile"]);
        }
        $s = Db::table("ic_staff")->where("id", $staff)->find();
        if (!$s) {
            return "客服不存在";
        }


        Log::info("autoReplayInfo_err2:");
        // 判断发送类型
        list($toUidNo, $seUidNo, $sendToNo) = $this->sendToSet($s["staff_no"], $u["no"], $usrType);

        // 聊天提示
        if ($sendToNo == "staff" && $s["status"] > 1) {
            // 客服忙碌
            chat::TisToUser($user, $staff, 0, "客服忙碌");
        }

        // 添加会话
        list($id, $type) = Chat::add($u, $user, $staff, $s, $agent, $data, $sendToNo);
        // 消息回复
        Chat::UpIsReply($sendToNo, $user, $staff);
        // 判断店铺信息 还是普通消息
        $chatType = 0;
        if ($store) $chatType = 1;
        // 添加记录
        $chatLog = ChatLog::add($store, $id, $user, $staff, $data, $agent, $sendToNo, $seUidNo, $s["staff_no"], $u["no"]);
        Log::info("是否客服：{$sendToNo}");
        // 发送消息 3 是离线
        if ($staffStatus < 3) {
            //获取信息
            $mess = $this->sendNew($id, $chatLog->id, $toUidNo, $seUidNo, $data, $staff, $sendToNo, $type, $isMen, $chatType);
            // ws 发送
            $this->sendToNo($toUidNo, $sendOtherNo, $mess);

            $mess_app = $this->sendNewApp($id, $chatLog->id, $toUidNo, $seUidNo, $data, $staff, $sendToNo, $type, $isMen, $chatType);
            $this->sendToNo($toUidNo, $sendOtherNo, $mess_app);
        } else if ($sendToNo == "staff") {
            // 企业微信发送
//            $corpId = Env::get("QYE.CORPID");
//            $secret = Env::get("QYE.APP_SECRET");
//            $agentId = Env::get("QYE.APP_AGENT");
//            $url = Env::get("QYE.APP_URL");
//            $we = new WeWork($corpId, $secret);
//            $userArr = [$s["qye_user_id"]];

            $corpId = Env::get("WXF.APP_ID");
            $secret = Env::get("WXF.APP_SE");
            $agentId = 0;
            $url = Env::get("WXF.APP_URL");
            $we = new WechatComment($corpId, $secret);
            $userArr = [$s["fwx_user_id"]];

            $token = Token::generateToken($s["staff_no"], "wx");
            $url = $url . "?token={$token}&chat_id={$id}&user_no={$u["no"]}";
            $we->setMessage($userArr, 0, $u["name"], $data, $url, $agentId, $s["staff_no"], $u["no"], $store);
            $res = $we->sendMessage();
            if ($res) Log::info("微信发送消息失败！：{$res}");
        }
        return "";
    }

    /**
     * 需要发送的人员 并且 发送给其他用户
     * @param $toUidNo
     * @param array $sendOtherNo
     * @param string $mess
     */
    public function sendToNo($toUidNo, $sendOtherNo = [], $mess = "")
    {
        if (empty($sendOtherNo)) {
            $toUidNoArr = [$toUidNo];
        } else {
            array_push($sendOtherNo, $toUidNo);
            $toUidNoArr = $sendOtherNo;
        }
        Log::info("sendToNo:" . json_encode($toUidNoArr));
        foreach ($toUidNoArr as $k => $v) {
            // 发送到的人
            self::sendToUid($v, $mess);
        }
    }

    /**
     * 发送消息内容 自动判断列表消息还是内容消息
     * @param $chatId
     * @param $logId
     * @param $toUidNo
     * @param $seUidNo
     * @param $data
     * @param $staffId
     * @param $sendToNo
     * @param int $type
     * @param int $isMen
     * @param int $chatType
     * @return string
     */
    public function sendNew($chatId, $logId, $toUidNo, $seUidNo, $data, $staffId, $sendToNo, $type = 0, $isMen = 0, $chatType = 0): string
    {
        if ($type) {
            $arr = $this->newListSend($chatId, $staffId, $sendToNo, $isMen, "", $chatType);
        } else {
            $arr = $this->newSend($chatId, $logId, $toUidNo, $seUidNo, $data, $sendToNo, $isMen, $chatType,$staffId);
        }
        $mess = wsJson("success", $arr);
        Log::info("send:{$toUidNo}-{$mess}");
        return $mess;
    }

    public function sendNewApp($chatId, $logId, $toUidNo, $seUidNo, $data, $staffId, $sendToNo, $type = 0, $isMen = 0, $chatType = 0): string
    {
        if ($type) {
            $arr = $this->newListSend($chatId, $staffId, $sendToNo, $isMen, "", $chatType);
        } else {
            $arr = $this->newSend($chatId, $logId, $toUidNo, $seUidNo, $data, $sendToNo, $isMen, $chatType,$staffId);
        }
        $arr['type'] = 'send_app';
        $mess_app = wsJson("success", $arr);
        Log::info("send:{$toUidNo}-{$mess_app}");
        return $mess_app;
    }

    // 列表数组
    public function voidNewList($chatId, $staffId): array
    {

        $arr = array(
            "chat_id" => $chatId,
            "user_no" => "",
            "user_icon" => "",
            "user_name" => "",
            "user_id" => "",
            "user_agent" => "",
            "update_time" => "",
            "last_info" => "",
            "last_info_status" => "",
            "send_to" => "",
            "store_url" => "",
            "store_title" => "",
            "store_img" => "",
            "store_address" => "",
            "store_industry" => "",
            "store_cost" => "",
            "store_pv" => "",
            "store_rent" => "",
            "store_square" => "",
            "chat_type" => "",
            "type" => "",
            "client_id" => "",
            "user_show" => "",
            "user_type" => "",
        );
        return $arr;
    }

    /**
     * 有用户消息发送列表内容
     * @param $id
     * @param $staffId
     * @param $sendToNo
     * @param $isMen
     * @param $data @自定义 获取数据
     * @param $chatType
     * @return array
     */
    public function newListSend($id, $staffId, $sendToNo, $isMen, $data, $chatType): array
    {
        $countLog = "sum(if(cl.status = 0,1,0)) as count_log";
        $list = Chat::alias('a')
            ->field("ss.pxs_id as store_id,a.id as chat_id,a.user_icon,a.user_name,a.user_id,a.user_agent
            ,a.update_time
            ,if(a.last_info is null,'',a.last_info) as last_info
            ,a.last_info_status,a.user_no,a.send_to,
             IFNULL(ss.url,'') as store_url,IFNULL(ss.title,'') as store_title,IFNULL(ss.img,'') as store_img,IFNULL(ss.address,'') as store_address,
            IFNULL(ss.industry,'') as store_industry,IFNULL(ss.cost,'') as store_cost,IFNULL(ss.pv,'') as store_pv,IFNULL(ss.rent,'') as store_rent,
            IFNUll(ss.square,'') as store_square,
            {$countLog}")
            ->leftjoin("ic_chat_log cl", "cl.chat_id = a.id")
            ->leftJoin("ic_user_pv_log ss", "ss.id = cl.store_id")
            ->where("a.staff_id", $staffId)
            ->where("a.id", $id)->order("a.id desc")
            ->find()->toArray();

        $staff = new Staff();
        $list['user_icon'] = $staff->getIconAttr($list["user_icon"]);

        $js = array(
            "chat_type" => $chatType,
            'type' => self::sendTypeList,
            'client_id' => '',
            "send_to" => $sendToNo,
            "user_show" => 1,
            "user_type" => $isMen, // 会员类型
        );
        if ($data) {
            $list["last_info"] = $data;
        }

        return array_merge($js, $list);
    }

    /**
     * 有用户消息发送内容
     * @param $chatId
     * @param $logId
     * @param $toUidNo
     * @param $seUidNo
     * @param $data
     * @param $sendToNo
     * @param $isMen
     * @param $chatType
     * @param $staffId
     * @return array
     */
    public function newSend($chatId, $logId, $toUidNo, $seUidNo, $data, $sendToNo, $isMen, $chatType, $staffId = ''): array
    {

        $list = ChatLog::alias('cl')
            ->field("ss.pxs_id as store_id,
             IFNULL(ss.url,'') as store_url,IFNULL(ss.title,'') as store_title,IFNULL(ss.img,'') as store_img,IFNULL(ss.address,'') as store_address,
            IFNULL(ss.industry,'') as store_industry,IFNULL(ss.cost,'') as store_cost,IFNULL(ss.pv,'') as store_pv,IFNULL(ss.rent,'') as store_rent,
            IFNUll(ss.square,'') as store_square,cl.user_agent,staff.staff_name as user_name,staff.icon as user_icon")
            ->leftJoin("ic_user_pv_log ss", "ss.id = cl.store_id");

        if(!empty($staffId)){
            $list = $list->leftJoin("ic_staff staff", "staff.id = cl.staff_id")
                ->where("cl.staff_id", $staffId);
        }
        $list = $list->where("cl.chat_id", $chatId)
            ->order("cl.id desc")
            ->find()->toArray();

        $staff = new Staff();
        $list['user_icon'] = $staff->getIconAttr($list["user_icon"]);

        $js = array(
            "chat_type" => $chatType,
            'type' => self::sendTypeInfo,
            'client_id' => '',
            'chat_id' => $chatId,
            "chat_log_id" => $logId,
            'to_user_no' => $toUidNo,
            'send_user_no' => $seUidNo,
            "info" => $data,
            "send_to" => $sendToNo,
            "user_type" => $isMen, // 会员类型
            'send_time' => date('Y-m-d H:i:s')
        );

        return array_merge($js, $list);
    }

    // ws cline_id 绑定 id 用户id(客服)
    public function wsStaffBind($clientId, $no, $id, $device_type): string
    {
        // 前缀
        $PreNo = self::$staPre . $no;
        Db::startTrans();
        try {
            $cli = new GateCli();
            $cli->newClient($clientId, $PreNo, $id);
            // 上线
            $st = $cli->staffRun($clientId, $no, $device_type);
            if ($st) {
                return $st;
            }
            // 向客户发送上线
            $userGroup = "user_group";
            $data = array(
                'type' => 'staff_online',
                'client_id' => $clientId,
                'user_no' => $no,
                "user_id" => $id,
            );
            $mess = wsJson("success", $data);
            self::sendToGroup($userGroup, $mess);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            return "绑定异常";
        }
        return "";
    }

    // 上线(客服)
    public function staffRun($clientId, $no, $device_type): string
    {
        $res = Staff::where("staff_no", $no)->find();
        if (!$res) {
            return "客服不存在~";
        }
        $arr = ["status" => 1];
        $res->save($arr);

        $resC = Conn::addCount($no, $device_type, $clientId, 1);
        if ($resC) {
            return $resC;
        }
        // 客服组添加
        $staffGroup = "staff_group";
        self::joinGroup($clientId, $staffGroup);
        return "";
    }

    // 下线(客服)
    public function staffOut($clientId, $no, $data): string
    {
        $res = Staff::where("staff_no", $no)->find();
        if (!$res) {
            return "没有改用户";
        }
        $arr = ["status" => 3];
        $res->save($arr);
        // 客服组离开
        $staffGroup = "staff_group";
        self::leaveGroup($clientId, $staffGroup);
        //  向客户发送通知
        $userGroup = "user_group";
        self::sendToGroup($userGroup, $data);

        // 获取有关联的客户
        $NoArr = Chat::field("user_no,id")->where("staff_no", $no)->select();
        if (!empty($NoArr)) {
            foreach ($NoArr as $ke => $vu){
                $idArrOnline = User::where("no", "in", $vu["user_no"])->where("status", 1)->column("id");
                foreach ($idArrOnline as $k => $v) {
                    $l = ChatLog::where("chat_id",$vu["id"])->order("id desc")->value("info");
                    if($l != Hint::getInfoByName("客服离开")) {
                        Chat::TisToUser($v, $res["id"], 0, "客服离开");
                    }
                }
            }
        }
        return "";
    }

    // ws cline_id 绑定 id 用户id(客户)
    public function wsUserBind($clientId, $no, $id, $isMen, $device_type): string
    {
        Log::info("wsUserBind");
        $PreNo = self::$usePre . $no;

        Db::startTrans();
        try {
            $cli = new GateCli();
            $cli->newManyClient($clientId, $PreNo, $id, $isMen);
            // 上线
            $st = $cli->userRun($clientId, $no, $device_type);
            if ($st) {
                return $st;
            }
            // 向客服发送上线
            $userGroup = "staff_group";
            $data = array(
                'type' => 'user_online',
                'client_id' => $clientId,
                'user_no' => $no,
                'user_id' => $id,
                "user_type" => $isMen,
            );
            $mess = wsJson("success", $data);
            self::sendToGroup($userGroup, $mess);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            return "异常";
        }
        return "";
    }

    // 上线(客户)
    public function userRun($clientId, $no, $device_type): string
    {
        $u = new User();
        $res = $u->where("no", $no)->find();
        if (!$res) {
//            $u->no = $no;
//            $u->name = "客户{$no}";
//            $u->status = 1;
//            $u->save();
        } else {
            $arr = ["status" => 1];
            $res->save($arr);
        }

        $resC = Conn::addCount($no, $device_type, $clientId, 0);
        if ($resC) {
            return $resC;
        }

        // 用户组添加
        $staffGroup = "user_group";
        self::joinGroup($clientId, $staffGroup);
        return "";
    }

    // 下线(客户)
    public function userOut($clientId, $no, $data): string
    {
        $res = User::where("no", $no)->find();
        if (!$res) {
            return "没有改用户";
        }
        $arr = ["status" => 3];
        $res->save($arr);
        // 客户离开
        $userGroup = "user_group";
        self::leaveGroup($clientId, $userGroup);
        //  向客服发送通知
        $staffGroup = "staff_group";
        self::sendToGroup($staffGroup, $data);

        // 获取有关联的客户
        $staffNoArr = Chat::field("staff_no,id")->where("user_no", $no)->select();
        if (!empty($staffNoArr)) {
            foreach ($staffNoArr as $ke => $vu) {
                $staffNoArrOnline = staff::where("staff_no", "in", $vu["staff_no"])->where("on_status", 1)->column("id");
                foreach ($staffNoArrOnline as $k => $v) {
                    $l = ChatLog::where("chat_id",$vu["id"])->order("id desc")->value("info");
                    if($l != Hint::getInfoByName("用户离开")){
                        Chat::TisToUser($res["id"], $v, 0, "用户离开");
                    }
                }
            }
        }
        return "";
    }

    // 当前状态
    public function staffStatus($no)
    {
        $status = self::isUidOnline(self::$staPre . $no);
        Log::info("staffStatus:$no.$status");
        return $status;
    }

    // 当前状态
    public function userStatus($no)
    {
        $status = self::isUidOnline(self::$usePre . $no);
        Log::info("userStatus:$no.$status");
        return $status;
    }

    // 获取是客服还是客户数据
    public function getUidByClientIdAndType($client_id): array
    {
        $uid = isset($_SESSION["{$client_id}no"]) ? $_SESSION["{$client_id}no"] : "";
        $staffNo = isset($_SESSION["{$client_id}staff_no"]) ? $_SESSION["{$client_id}staff_no"] : "";
        $userNo = isset($_SESSION["{$client_id}user_no"]) ? $_SESSION["{$client_id}user_no"] : "";
        $id = isset($_SESSION["id"]) ? $_SESSION["id"] : 0;

        $isMen = isset($_SESSION["isMen"]) ? $_SESSION["isMen"] : 0;

        if (isset($_SESSION)) Log::info("getUidByClientIdAndType:" . json_encode($_SESSION));

        if (!$uid) {
            return ["err", "{$client_id}_{$uid}已离线"];
        }
        $uidSub = substr($uid, 0, 4);
        return [$uidSub, substr($uid, 4), $staffNo, $userNo, $id, $isMen];
    }

    // 释放session
    public function unsetSession($client_id)
    {
        unset($_SESSION["no"]);
        unset($_SESSION["staff_no"]);
        unset($_SESSION["user_no"]);
    }

    // 修改信息通知(客户)
    public function userUpNew($staffNo, $staffId, $chatId, $isMen)
    {
        $clientId = "";
        $data = array(
            'type' => 'up_info_notice',
            'client_id' => $clientId,
            'no' => $staffNo,
            'id' => $staffId,
            "chat_id" => $chatId,
            "user_type" => $isMen,
        );
        $mess = wsJson("success", $data);
        self::sendToUid(self::$staPre . $staffNo, $mess);
    }

    // 修改信息通知(客服)
    public function staffUpNew($userNo, $userId, $chatId, $isMen)
    {
        $clientId = "";
        $data = array(
            'type' => 'up_info_notice',
            'client_id' => $clientId,
            'no' => $userNo,
            'id' => $userId,
            "chat_id" => $chatId,
            "user_type" => $isMen,
        );
        $mess = wsJson("success", $data);
        self::sendToUid(self::$usePre . $userNo, $mess);
    }

    // 添加时长
    public function addTimeLong($staffNo, $date_arr)
    {
        $s = strtotime(date("Y-m-d", time()));

    }

    // 客服转接ws提示
    public function tisToStaffSendUser($staffNo, $newStaffNo, $userNo, $server_type)
    {

        $u = User::where("no", $userNo)->find();
        $res = Staff::alias("s")
            ->leftJoin("ic_token t", "t.staff_no = s.staff_no")
            ->field("s.id,s.staff_no,s.staff_name,s.icon,t.device_type as user_agent")
            ->where("s.staff_no", $newStaffNo)->find();

        $data = array(
            'type' => 'up_staff_no_notice',
            'client_id' => "",
            'user_no' => $userNo,
            "old_staff_no" => $staffNo,

            "staff_no" => $newStaffNo,
            "staff_name" => $res["staff_name"],
            "icon" => $res["icon"],
            "user_agent" => $res["user_agent"],

            "type_name" => "转接客服通知"
        );
        $mess = wsJson("success", $data);
        Log::info("新旧用户绑定: 内容{$mess}");

        try {
            // 客户 转接 信息
            $ToUid = $this->getUserNo($userNo);
            self::sendToUid($ToUid, $mess);

            // 客服与客户 转让 系统问候
            $ToUid2 = $this->getStaffNo($newStaffNo);
            $tisStaff = $ToUid2;

            $isMen = User::getIsMen($u["mobile"]);
            $name = mb_substr($res["staff_name"], 0, 1);
            $sendData = "您好~我金牌{$name}客服,有什么能帮到你？";

            $resSend = $this->SendToUser($res["id"], $u["id"], $server_type, 0, $sendData, self::toTypeUse, $isMen, 0, [$tisStaff]);
            if ($resSend) {
                Log::info("新旧用户绑定: 转让客服发送信息{$mess}");
            }
        } catch (DbException $e) {
            Log::info("tisToStaffSendUser:{$e->getMessage()}");
        }

    }
}